use lazy_static::lazy_static;
use rand::{thread_rng, Rng};
use regex::Regex;
use std::env;
use std::io::{self, BufRead};
use std::iter::Iterator;

lazy_static! {
    static ref RE: Regex = { Regex::new(r"(^\d{1,})[,\.a-zA-Z_-](\d{1,})$").unwrap() };
}

struct Dice {
    amount: usize,
    sides: usize,
}

impl Dice {
    fn from_str(description: &str) -> Option<Dice> {
        let cg = RE.captures(description)?;
        let amount_match = cg.get(1)?;
        let sides_match = cg.get(2)?;

        let amount: usize = amount_match.as_str().parse().unwrap_or(1);
        let sides: usize = sides_match.as_str().parse().unwrap_or(0);

        Some(Dice { amount, sides })
    }

    fn roll(&self) -> Vec<usize> {
        let mut rng = thread_rng();
        let sides = self.sides + 1;
        (0..self.amount).map(|_| rng.gen_range(1, sides)).collect()
    }

    fn null_die() -> Dice {
        Dice {
            amount: 0,
            sides: 0,
        }
    }
}

fn handle_input<I>(descriptions: I)
where
    I: IntoIterator<Item = String>,
{
    let mut result: usize = 0;

    for description in descriptions.into_iter() {
        let dice = Dice::from_str(description.as_ref()).unwrap_or(Dice::null_die());

        if dice.amount == 0 || dice.sides == 0 {
            continue;
        };

        let rolls = dice.roll();
        let mut sum = 0;

        for roll in &rolls {
            sum += roll;
        }
        result += sum;

        let description = format!("{}d{}", dice.amount, dice.sides);
        println!("Rolled {:>6}: {:>4} ({:?})", description, sum, rolls);
    }
    println!("             = {:>4}", result);
}

fn main() {
    let args = env::args().skip(1);

    if args.len() > 0 {
        handle_input(args);
    } else {
        let stdin = io::stdin();

        for line in stdin.lock().lines() {
            let args = match line {
                Ok(line) => line.split_whitespace().map(|arg| arg.to_owned()).collect(),
                _ => vec![],
            };
            handle_input(args);
        }
    }
}
